import { Constructor } from "cc";
import { ECSEntity } from "./ECSEntity";
import { ECSSys } from "./ECSSys";
import { FilterBuilder } from "./FilterBuilder";
import { ArrayMap } from "../../struct/ArrayMap";

export enum ECSWorldState {
    None,
    /** 运行中 */
    Playing,
    /** 暂停中 */
    Pause,
}

export class ECSWorld {
    private _entityId: number = 0;
    private _systemId: number = 0;

    private _entityMap: ArrayMap<number, ECSEntity> = new ArrayMap();
    private _sysMap: Map<number, ECSSys> = new Map();
    private _prioritySys: number[] = [];

    private _state: ECSWorldState = 0;
    get state(): ECSWorldState { return this._state; }

    /**
     * 创建实体
     * @param cls 
     * @returns 
     */
    createEntity<T extends ECSEntity>(cls: Constructor<T>) {
        const entity = new cls(this._entityId++, this);
        this._entityMap.set(entity.id, entity);
        return entity;
    }

    /**
     * 是否包含实体
     * @param id 
     * @returns 
     */
    hasEntity(id: number): boolean {
        return this._entityMap.has(id);
    }

    /**
     * 获取实体
     * @param id 
     * @returns 
     */
    getEntity(id: number): ECSEntity | null {
        return this._entityMap.get(id)
    }

    /**
     * 设置实体启用状态
     * @param id 
     * @param enable 
     */
    setEntityEnable(id: number, enable: boolean): void {
        if (this.hasEntity(id)) {
            this.getEntity(id).enable = enable
        }
    }


    /**
     * 销毁实体
     * @param id 
     */
    destroyEntity(id: number): void {
        if (this.hasEntity(id)) {
            const entity = this.getEntity(id)
            entity._ecsDestroy()
            this._entityMap.delete(id)
            this._sysMap.forEach(sys => sys.removeEntity(id))
        }
    }

    /**
     * 销毁所有实体
     */
    destroyAllEntity() {
        const keys = [...this._entityMap.keys]
        keys.forEach(key => this.destroyEntity(key));
    }

    /**
     * 创建系统
     * @param cls 
     * @param priority 
     */
    createSys<T extends ECSSys>(cls: Constructor<T>, priority: number = 0, filter?: FilterBuilder) {
        const sys = new cls(this, this._systemId++, priority, filter);
        this._sysMap.set(sys.id, sys);
        return sys;
    }

    /**
     * 是否存在系统
     * @param id 
     * @returns 
     */
    hasSys(id: number) {
        return this._sysMap.has(id);
    }

    /**
     * 获取系统
     * @param id 
     * @returns 
     */
    getSys(id: number) {
        return this._sysMap.get(id);
    }

    /** 
     * 移除系统 
     */
    destroySys(id: number): void {
        if (this.hasSys(id)) {
            const sys = this.getSys(id);
            sys._ecsDestroy();
            this._sysMap.delete(id);
        }
    }

    /**
     * 移除所有系统
     */
    destroyAllSys(): void {
        const keys = [...this._sysMap.keys()];
        keys.forEach(key => this.destroySys(key));
    }


    /**
     * 设置系统是否可用
     * @param id 
     * @param enable 
     */
    setSysEnable(id: number, enable: boolean): void {
        if (this.hasSys(id)) {
            this.getSys(id).enable = enable;
        }
    }


    /**
     * 刷新系统里面的所有实体
     */
    updateSysEntity() {
        const sysAr = Array.from(this._sysMap.values())
        this._prioritySys = sysAr.sort((a, b) => b.priority - a.priority).map(sys => sys.id);
        for (const id of this._prioritySys) {
            if (this.hasSys(id)) {
                const sys = this.getSys(id);
                sys.removeAllEntity()
                this._entityMap.values.forEach(entity => {
                    sys.addEntity(entity.id)
                })
            }
        }
    }

    /** 更新世界 */
    update(dt: number): void {
        if (this._state != ECSWorldState.Playing) return;
        this._entityMap.values.forEach(entity => entity._ecsUpdate(dt));
        this._prioritySys.forEach(id => {
            if (this.hasSys(id)) {
                this.getSys(id)._ecsUpdate(dt);
            }
        });
    }


    /**
     * ecs运行过程中实体组件变化,对应系统更新
     * 1:组件添加减少调用
     * 2:标签变化
     * 3:组件可用
     * @param entity 
     */
    onEntityMatch(entity: ECSEntity): void {
        // ecs运行之前不调用
        if (this._state == ECSWorldState.None) return

        // 只重新检查这个实体在哪些系统中
        this._sysMap.forEach(sys => {
            const hasEntity = sys.hasEntity(entity.id);
            const shouldMatch = sys.match(entity);

            if (shouldMatch && !hasEntity) {
                sys.addEntity(entity.id);
            } else if (!shouldMatch && hasEntity) {
                sys.removeEntity(entity.id);
            }
        });
    }



    /**
     * 启动
     */
    start(): void {
        this.updateSysEntity()
        this._state = ECSWorldState.Playing;
    }

    /**
     * 暂停
     */
    pause(): void {
        this._state = ECSWorldState.Pause;
    }

    /**
     * 恢复
     */
    resume(): void {
        this._state = ECSWorldState.Playing;
    }

    /** 
     * 销毁世界 
     */
    destroy(): void {
        this.destroyAllSys()
        this.destroyAllEntity()
        this._sysMap.clear()
        this._prioritySys.length = 0
        this._entityMap.clear()
        this._state = ECSWorldState.None;
    }
}